// 1. 防抖/截流
// 2. curry/compose
// 3. call/applay/bind

function debounce(fn, delay) {
    let timer = null;
    return (...args) => {
        if (timer) clearTimeout(timer);
        timer = setTimeout(() => {
            fn.call(this, ...args)
        }, delay)
    }
}

function betterDebounce(fn, delay, immediate) {
    let timer = null;
    return (...args) => {
        if (!timer && immediate) {
            timer = setTimeout(() => {
                timer = null
            }, delay)
            fn.call(this, ...args)
        } else {
            if (timer) clearTimeout(timer)
            timer = setTimeout(() => {
                fn.call(this, ...args)
            }, delay)
        }
    }
}

function throttle(fn, delay) {
    let timer = null;
    return (...args) => {
        if (timer) return;
        timer = setTimeout(() => {
            fn.call(this, ...args)
            timer = null
        }, delay)
    }
}

function bertterThrottle(fn, delay) {
    let timer = null
    let start = Date.now();
    return (...args) => {
        let current = Date.now();
        let wait = delay - (current - start);
        if (wait <= 0) {
            clearTimeout(timer)
            timer = null
            fn.call(this, ...args)
            start = Date.now()
        } else {
            if (timer) return;
            timer = setTimeout(() => {
                fn.call(this, ...args)
                timer = null
                start = Date.now()
            }, wait)
        }
    }
}

function compose(...arr){
    return (val) => {
        return arr.reduceRight((pre,next) => next(pre), val)
    }
}
let f1 = (a) => a + a;
let f2 = (a) => a * a; 
console.log(compose(f1, f2)(3))

function curry(fn){
    function curryFn(...args){
        if(fn.length > args.length){
            return function(...params){
                return curryFn.call(this, ...args.concat(params))
            }
        } else {
            return fn.call(this, ...args)
        }
    }
    return curryFn
}
var a = (a, b, c, d) => a+b+c+d
let newFn = curry(a);
console.log(newFn(1, 2)(3)(3,4))

function curry2(...args){
    let arr = [...args];
    function sumFn(...params){
        arr = [...arr, ...params]
        return sumFn
    }
    sumFn.values = function(){
        return arr.reduce((a, b) => a + b, 0)
    }
    return sumFn
}
console.log(curry2(2)(1,3).values())


Function.prototype.myCall = function(context, ...args){
        let key = Symbol()
        context[key] = this;
        let res = context[key](...args)
        delete context[key]
        return res;
}

Function.prototype.myAplly = function(context, ...args){
        let key = Symbol()
        context[key] = this;
        let res;
        if(Array.isArray(args)){
         res = context[key](...args)
        } else {
            res = context[key]()
        }
        delete context[key]
        return res;
}

Function.prototype.myBind = function(context, ...args){
    return (...params) => {
        let key = Symbol()
        context[key] = this;
        let res = context[key](...params)
        delete context[key]
        return res;
    }
}